﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using Magellan.ProjectWizards.Framework;

namespace Magellan.ProjectWizards.Setup.SetupTemplate
{
    public class SetupRunner
    {
        public SetupRunner()
        {
            CreatedProjects = new List<string>();
        }

        public string DependenciesSourceDirectory { get; set; }
        public List<string> CreatedProjects { get; private set; }
        
        public void Execute(SetupModel model, Dictionary<string, string> replacementsDictionary)
        {
            var rootDirectory = Path.GetDirectoryName(replacementsDictionary["$destinationdirectory$"]);

            if (model.CopyLibraries == false)
            {
                model.LibraryDirectory = DependenciesSourceDirectory;
            }

            // Copy the dependencies
            CopyDependencies(model);

            // Add some of our own replacements
            replacementsDictionary.Add("$primaryprojectname$", replacementsDictionary["$safeprojectname$"]);
            replacementsDictionary.Add("$primaryprojectguid$", "{" + Guid.NewGuid().ToString().ToUpper() + "}");
            replacementsDictionary.Add("$testprojectguid$", "{" + Guid.NewGuid().ToString().ToUpper() + "}");
            
            // Make dependencies available
            replacementsDictionary.Add("$magellandllpath$", PathHelper.GetRelativePath(rootDirectory + "\\Foo\\Bar", Path.Combine(model.LibraryDirectory, "Magellan.dll")));
            replacementsDictionary.Add("$interactivitypath$", PathHelper.GetRelativePath(rootDirectory + "\\Foo\\Bar", Path.Combine(model.LibraryDirectory, "System.Windows.Interactivity.dll")));
            if (model.CreateTestProject)
            {
                replacementsDictionary.Add("$nunitpath$", PathHelper.GetRelativePath(rootDirectory + "\\NUnit\\Foo", Path.Combine(model.LibraryDirectory, "nunit.framework.dll")));
            }

            // Setup generator
            var generator = new ProjectGenerator("Setup.SetupTemplate", rootDirectory, replacementsDictionary);

            // The main project
            generator.RenderFile("Project/Project.csproj", "$safeprojectname$/$safeprojectname$.csproj");
            generator.RenderFile("Project/Controllers/HomeController.cs", "$safeprojectname$/Controllers/HomeController.cs");
            generator.RenderFile("Project/Properties/AssemblyInfo.cs", "$safeprojectname$/Properties/AssemblyInfo.cs");
            generator.RenderFile("Project/Views/Home/Add.xaml", "$safeprojectname$/Views/Home/Add.xaml");
            generator.RenderFile("Project/Views/Home/Add.xaml.cs", "$safeprojectname$/Views/Home/Add.xaml.cs");
            generator.RenderFile("Project/Views/Home/AddModel.cs", "$safeprojectname$/Views/Home/AddModel.cs");
            generator.RenderFile("Project/Views/Home/Index.xaml", "$safeprojectname$/Views/Home/Index.xaml");
            generator.RenderFile("Project/Views/Home/Index.xaml.cs", "$safeprojectname$/Views/Home/Index.xaml.cs");
            generator.RenderFile("Project/App.xaml", "$safeprojectname$/App.xaml");
            generator.RenderFile("Project/App.xaml.cs", "$safeprojectname$/App.xaml.cs");
            generator.RenderFile("Project/Window1.xaml", "$safeprojectname$/Window1.xaml");
            generator.RenderFile("Project/Window1.xaml.cs", "$safeprojectname$/Window1.xaml.cs");

            CreatedProjects.Add(Path.Combine(rootDirectory, replacementsDictionary["$safeprojectname$"] + "\\" + replacementsDictionary["$safeprojectname$"] + ".csproj"));
            
            // The test project
            if (model.CreateTestProject)
            {
                replacementsDictionary["$safeprojectname$"] = model.TestProjectName;
                replacementsDictionary["$projectguid$"] = model.TestProjectName;
                CreatedProjects.Add(Path.Combine(rootDirectory, replacementsDictionary["$safeprojectname$"] + "\\" + replacementsDictionary["$safeprojectname$"] + ".csproj"));

                generator.RenderFile("Project.Tests/Project.Tests.csproj", "$safeprojectname$/$safeprojectname$.csproj");
                generator.RenderFile("Project.Tests/Controllers/HomeControllerTests.cs", "$safeprojectname$/Controllers/HomeControllerTests.cs");
                generator.RenderFile("Project.Tests/Properties/AssemblyInfo.cs", "$safeprojectname$/Properties/AssemblyInfo.cs");
            }
        }

        private void CopyDependencies(SetupModel model)
        {
            if (!model.CopyLibraries)
                return;

            Directory.CreateDirectory(model.LibraryDirectory);
            CopyFile("Magellan.dll", model.LibraryDirectory);
            CopyFile("Magellan.pdb", model.LibraryDirectory);
            CopyFile("Magellan.xml", model.LibraryDirectory);
            CopyFile("Magellan.Transitionals.dll", model.LibraryDirectory);
            CopyFile("Magellan.Transitionals.pdb", model.LibraryDirectory);
            CopyFile("Magellan.Transitionals.xml", model.LibraryDirectory);
            CopyFile("Transitionals.dll", model.LibraryDirectory);
            CopyFile("System.Windows.Interactivity.dll", model.LibraryDirectory);
            if (model.CreateTestProject)
            {
                CopyFile("NUnit\\nunit.framework.dll", model.LibraryDirectory);
            }
        }

        private void CopyFile(string sourcePath, string targetDirectory)
        {
            var fullSourcePath = Path.GetFullPath(Path.Combine(DependenciesSourceDirectory, sourcePath));
            var fullTargetPath = Path.GetFullPath(Path.Combine(targetDirectory, Path.GetFileName(fullSourcePath)));

            Trace.WriteLine(string.Format("Copying file '{0}' to destination '{1}'", fullSourcePath, fullTargetPath));
            if (File.Exists(fullTargetPath))
            {
                Trace.WriteLine(string.Format("The file '{0}' already exists. It will be skipped.", fullTargetPath));
            }
            else
            {
                File.Copy(fullSourcePath, fullTargetPath, true);
            }
        }
    }
}
